﻿using ClassLibrary;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace RDPProxyServer
{
    public partial class Form1 : Form
    {
        Thread _thread;
        private string PortServerKey = "PortServer";
        private string PortClienToServerKey = "PortClienToServer";
        private bool _exitApp = false;

        #region 核心代码

        private Dictionary<int, TcpClient> _dic = new Dictionary<int, TcpClient>();
        private NetworkStream _kongzhins = null;

        private bool _isStart = false;

        private TcpListener _tl1;

        private TcpListener _tl2;

        private ErrMessageQueue errList = new ErrMessageQueue();


        public void Start1(object obj)
        {
            _tl1 = new TcpListener(IPAddress.Any, Convert.ToInt32(portClienToServer.Value));//开一个对方可以连接的端口     
            _tl1.Start();
            while (_isStart)
            {
                try
                {
                    TcpClient tc = _tl1.AcceptTcpClient();
                    Jieshou(tc);
                }
                catch (Exception ex)
                {
                    errList.Enqueue("[1]" + ex.Message);
                }
            }
        }
        public void Start2(object obj)
        {
            _tl2 = new TcpListener(IPAddress.Any, Convert.ToInt32(portServer.Value)); //开一个随意端口让自己的mstsc连。
            //_tl2.Stop();
            _tl2.Start();
            while (_isStart)
            {
                try
                {
                    TcpClient tc = _tl2.AcceptTcpClient();
                    Random rnd = new Random();
                    int biaoji = rnd.Next(1000000000, 2000000000);
                    _dic.Add(biaoji, tc);
                    byte[] bt = BitConverter.GetBytes(biaoji);
                    _kongzhins.Write(bt, 0, bt.Length);
                }
                catch (Exception ex)
                {
                    errList.Enqueue("[2]" + ex.Message);
                }
            }
        }

        private void Jieshou(TcpClient tc)
        {
            //这里体现的是一个配对的问题，自己体会一下吧  
            NetworkStream ns = tc.GetStream();
            byte[] bt = new byte[4];
            int count = ns.Read(bt, 0, bt.Length);
            if (count == 2 && bt[0] == 0x6f && bt[1] == 0x6b)
            {
                _kongzhins = ns;
            }
            else
            {
                int biaoji = BitConverter.ToInt32(bt, 0);
                Lianjie(biaoji, tc);
            }
        }

        private void Lianjie(int biaoji, TcpClient tc1)
        {
            TcpClient tc2 = null;
            if (_dic.ContainsKey(biaoji))
            {
                _dic.TryGetValue(biaoji, out tc2);
                _dic.Remove(biaoji);
                tc1.SendTimeout = 30 * 1000;
                tc1.ReceiveTimeout = 30 * 1000;
                tc2.SendTimeout = 30 * 1000;
                tc2.ReceiveTimeout = 30 * 1000;
                object obj1 = (object)(new[] { tc1, tc2 });
                object obj2 = (object)(new[] { tc2, tc1 });
                ThreadPool.QueueUserWorkItem(Transfer, obj1);
                ThreadPool.QueueUserWorkItem(Transfer, obj2);
            }
        }

        private void Transfer(object obj)
        {
            TcpClient tc1 = ((TcpClient[])obj)[0];
            TcpClient tc2 = ((TcpClient[])obj)[1];
            NetworkStream ns1 = tc1.GetStream();
            NetworkStream ns2 = tc2.GetStream();
            while (true)
            {
                try
                {
                    //这里必须try catch，否则连接一旦中断程序就崩溃了，要是弹出错误提示让机主看见那就囧了  
                    byte[] bt = new byte[10240];
                    int count = ns1.Read(bt, 0, bt.Length);
                    ns2.Write(bt, 0, count);
                }
                catch (Exception ex)
                {
                    errList.Enqueue("[3]" + ex.Message);
                    ns1.Dispose();
                    ns2.Dispose();
                    tc1.Close();
                    tc2.Close();
                    break;
                }
            }
        }

        private void StartServer()
        {
            try
            {
                ThreadPool.QueueUserWorkItem(Start1);
                ThreadPool.QueueUserWorkItem(Start2);
                WaitHandle.WaitAll(new WaitHandle[] { new ManualResetEvent(false) });
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);

                errList.Enqueue("[4]" + ex.Message);
            }

        }
        #endregion

        public Form1()
        {
            InitializeComponent();
        }
        private void BtnStart_Click(object sender, EventArgs e)
        {
            if (Utility.PortInUse(Convert.ToInt32(portServer.Value)))
            {
                MessageBox.Show($"端口[{portServer.Value}]已被占用。");
                return;
            }
            if (Utility.PortInUse(Convert.ToInt32(portClienToServer.Value)))
            {
                MessageBox.Show($"端口[{portClienToServer.Value}]已被占用。");
                return;
            }
            Utility.UpdateAppConfig("PortServer", portServer.Value.ToString());
            Utility.UpdateAppConfig("PortClienToServer", portClienToServer.Value.ToString());

            _isStart = true;
            btnStart.Enabled = !_isStart;
            btnStop.Enabled = _isStart;

            _thread = new Thread(StartServer);
            _thread.Start();

            if (!backgroundWorker1.IsBusy)
            {
                backgroundWorker1.RunWorkerAsync();
            }


        }

        private void BtnStop_Click(object sender, EventArgs e)
        {
            try
            {
                _isStart = false;
                btnStart.Enabled = !_isStart;
                btnStop.Enabled = _isStart;
                _tl1.Stop();
                _tl2.Stop();
                _thread.Abort();
                _thread.Join();

                backgroundWorker1.CancelAsync();
            }
            catch (Exception ex)
            {

                errList.Enqueue(ex.Message);
            }
        }

        private void RichTextBox1_TextChanged(object sender, EventArgs e)
        {

        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (!_exitApp)
            {
                e.Cancel = true;
                this.WindowState = FormWindowState.Minimized;
                return;
            }
            btnStop.PerformClick();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //CheckForIllegalCrossThreadCalls = false;
            this.Height = 170;
            richTextBox1.Visible = false;
            btnStart.Enabled = !_isStart;
            btnStop.Enabled = _isStart;

            var port1 = Utility.GetAppConfig(PortServerKey);
            if (!string.IsNullOrEmpty(port1))
            {
                portServer.Value = Convert.ToInt16(port1);
            }
            var port2 = Utility.GetAppConfig(PortClienToServerKey);
            if (!string.IsNullOrEmpty(port2))
            {

                portClienToServer.Value = Convert.ToInt16(port2);
            }
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            while (!backgroundWorker1.CancellationPending || errList.Count > 0)
            {
                if (errList.Count == 0)
                {
                    continue;
                }
                var errMessage = errList.Dequeue();
                richTextBox1.SelectionStart = 0;
                richTextBox1.SelectionColor = Color.Black;
                richTextBox1.SelectedText = errMessage.err + Environment.NewLine;
                richTextBox1.SelectionStart = 0;
                richTextBox1.SelectionColor = Color.Red;
                richTextBox1.SelectedText = errMessage.date;

                if (richTextBox1.Lines.Length > 15)
                {
                    //MessageBox.Show(richTextBox1.Lines[richTextBox1.Lines.Length-2]);

                    var index = richTextBox1.Text.LastIndexOf(richTextBox1.Lines[richTextBox1.Lines.Length - 2], StringComparison.Ordinal);
                    richTextBox1.Select(index, richTextBox1.TextLength - index);
                    richTextBox1.SelectedText = "";

                }
                //Thread.Sleep(1000);
            }
        }


        private void btnShowErr_Click(object sender, EventArgs e)
        {
            if (this.Height == 500)
            {
                this.Height = 150;
                richTextBox1.Visible = false;
            }
            else
            {
                this.Height = 500;
                richTextBox1.Visible = true;
            }
        }

        private void btnExit_Click(object sender, EventArgs e)
        {
            _exitApp = true;
            this.Close();
        }

        private void notifyIcon1_Click(object sender, EventArgs e)
        {
            notifyIcon1.Visible = false;
            this.Show();
            WindowState = FormWindowState.Normal;
            this.Activate();
        }

        private void Form1_Resize(object sender, EventArgs e)
        {
            if (WindowState == FormWindowState.Minimized)
            {
                this.notifyIcon1.Visible = true;
                this.Hide();
                this.notifyIcon1.ShowBalloonTip(3, "提示", "程序仍在运行！\n点击图标显示。", ToolTipIcon.Info);
            }
        }
    }

}
